
import mysql from 'mysql';
import logger from '../logger';
import { Response, Request } from 'express';
const conf = require('./../../conf/conf.json');
logger.info(`db info: host: ${conf.db.host} user: ${conf.db.user} pwd: ${conf.db.pwd} dbname: ${conf.db.dbname}`);
var connection = mysql.createConnection({
    host: conf.db.host,
    port: conf.db.port,
    user: conf.db.user,
    password: conf.db.pwd,
    database: conf.db.dbname,
    multipleStatements: true //update 的时候执行多条update语句。
});
connection.on('error', (err: mysql.MysqlError) => {
    logger.error('on mysql error,errno: ', err.errno, ' errmsg: ', err.message);
});
const tableName = 'tb_service_info';
connection.query(`SELECT 1 + 1;`, null, (err) => {//测试mysql是否可用.
    if (err) {
        logger.error('mysql connection failed. err: ', err.message, ' errno: ', err.errno);
    }
});



function sendMysqlErr(res: any, err: any, sql: string = "") {
    if (err) {
        logger.error('执行的sql语句: ' + sql);
        logger.error(`mysql error, errno: ${err.errno}, errcode: ${err.code}, errmsg: ${err.sqlMessage}`);
        res.send({
            result: -1,
            msg: 'mysql error.'
        });
    }
}
export class RedisHost {
    port: number = 0;
    host: string = '';
    static equals(l: RedisHost, r: RedisHost): boolean {
        if ((l.port === r.port)
            && (l.host === r.host)) {
            return true;
        }
        return false;
    }
}
export class Service {
    serviceId: number = -1;
    redisCluster: RedisHost[] = [];
    mysqlAddr: string = '';
    mysqlPort: number = 330;
    mysqlUser: string = '';
    mysqlPwd: string = '';
    mysqlDbname: string = '';
    wxServiceAddr: string = '';
    agentAddr: string = '';
    allowedAppids: string[] = [];
    description: string = '';
    status: number = 1;
    msg: string = 'ok';

    equals(other: Service): boolean {
        if (this.serviceId === other.serviceId
            && this.mysqlAddr === other.mysqlAddr
            && this.mysqlPort === other.mysqlPort
            && this.mysqlUser === other.mysqlUser
            && this.mysqlPwd === other.mysqlPwd
            && this.mysqlDbname === other.mysqlDbname
            && this.wxServiceAddr === other.wxServiceAddr
            && this.agentAddr === other.agentAddr) {
            if ((this.redisCluster.length !== other.redisCluster.length)
                || (this.allowedAppids.length !== other.allowedAppids.length)) {
                return false;
            }
            for (var i in this.redisCluster) {
                if (!RedisHost.equals(other.redisCluster[i], this.redisCluster[i])) {
                    return false;
                }
            }

            for (var i in this.allowedAppids) {
                if (other.allowedAppids[i] !== this.allowedAppids[i]) {
                    return false;
                }
            }
            return true;
        }
        return false;
    }
}

export class ServiceList {
    private wsAddr: string = '';
    public servicdLists: Service[] = [];
    private result: number = 1;
    private msg: string = 'ok';
    setWsAddr(wsAddr: string) {
        this.wsAddr = wsAddr;
    }
    addService(serviceObj: Service) {
        this.servicdLists.push(serviceObj);
    }
    setResult(nResult: number) {
        this.result = nResult;
    }
    setMsg(msg: string) {
        this.msg = msg;
    }
}


type GetServicesCb = (err: Error | null, sl: ServiceList) => void;

class MysqlHandler {
    strWsAddr: string = '';
    constructor(strWsAddr: string) {
        this.strWsAddr = strWsAddr;
    }

    // 获取服务列表。
    getServiceList(res: Response) {
        var sql = 'select id,allowedAppids,description,status,msg from tb_service_info';
        connection.query(sql, (err: any, results: any) => {
            if (!err) {
                var retObj = new ServiceList();
                retObj.setWsAddr(this.strWsAddr);
                var nLen = results.length;
                var nResult = 1;
                var strErrmsg: string = 'ok';
                for (var i = 0; i < nLen; ++i) {
                    var entry = results[i];
                    var allowedAppidsObj = null;
                    try {
                        allowedAppidsObj = JSON.parse(results[i].allowedAppids);//如果allowedAppids不是json对象，解析会出异常，这里需要补货。
                    }
                    catch (e) {
                        logger.error('解析allowedAppids失败，内容： ' + results[i].allowedAppids + ' servicdId: ' + entry.id);
                        nResult = -1;
                        strErrmsg = '解析allowedAppids失败, serviceId: ' + entry.id;
                        break;
                    }
                    var service: Service = new Service();
                    service.serviceId = entry.id;
                    service.allowedAppids = allowedAppidsObj;
                    service.description = entry.description;
                    service.status = entry.status;
                    service.msg = entry.msg;
                    retObj.addService(service);
                }
                retObj.setMsg(strErrmsg);
                retObj.setResult(nResult);
                res.send(JSON.stringify(retObj));
            }
            else {
                sendMysqlErr(res, err, sql);
            }
        });
    }
    // 增加服务信息，一次可以增加多个
    addServices(req: Request, res: Response) {
        var data: string = '';
        req.on('data', (chunk: string) => {
            data += chunk;
        });

        req.on('end', () => {
            // logger.info(data);
            var entryArr = JSON.parse(data);
            var nLen = entryArr.length;
            // var sql = `INSERT INTO ${tableName} SET ? `;
            var sql = `INSERT INTO ${tableName}(redisCluster,mysqlAddr,mysqlPort,mysqlUser,mysqlPwd,mysqlDbname,wxServiceAddr,agentAddr,allowedAppids,description) values ?  `;
            var sqlAllParams = [];

            for (var i = 0; i < nLen; ++i) {
                var entryObj = entryArr[i];
                var tmpArr = [
                    JSON.stringify(entryObj.redisCluster), entryObj.mysqlAddr, entryObj.mysqlPort, entryObj.mysqlUser,
                    entryObj.mysqlPwd, entryObj.mysqlDbname, entryObj.wxServiceAddr, entryObj.agentAddr,
                    JSON.stringify(entryObj.allowedAppids), entryObj.description,
                ];
                sqlAllParams.push(tmpArr);
            }
            connection.query(sql, [sqlAllParams], (err: any, result: any) => {
                if (err) {
                    sendMysqlErr(res, err, sql);
                    return;
                }
                res.send({
                    affectedRows: result.affectedRows,
                    result: 1,
                    msg: 'ok'
                });
            });
        });
    }
    delServices(req: Request, res: Response) {
        var data: string = '';
        req.on('data', (chunk: string) => {
            data += chunk;
        });
        req.on('end', () => {
            var dataObj = null;
            var nResult = 1;
            var strErrmsg = 'ok';
            try {
                dataObj = JSON.parse(data);
            }
            catch (e) {
                logger.error(e);
                nResult = -1;
                strErrmsg = "json parse failed."
            }
            if (dataObj) {//数据解析成功。
                var sql = `delete from ${tableName} where id in(?)`;
                connection.query(sql, [dataObj.serviceIds], (err: any, result: any) => {
                    if (err) {
                        logger.error('sql excute failed. msg: ' + err.sqlMessage);
                        sendMysqlErr(res, err, sql);
                        return;
                    }
                    res.send({
                        affectedRows: result.affectedRows,
                        result: nResult,
                        msg: strErrmsg
                    });
                });
                return;
            }

            res.send({
                result: nResult,
                msg: strErrmsg
            });
        });
    }

    updateService(req: Request, res: Response) {
        logger.info(req);
        var data: string = '';
        req.on('data', (chunk: string) => {
            data += chunk;
        })
        req.on('end', () => {
            var updateArr = null;
            var nResult = 1;
            var strErrmsg = "ok";
            try {
                updateArr = JSON.parse(data);
            }
            catch (e) {
                logger.error(e);
                nResult = -1;
                strErrmsg = "json parse failed."
                res.send({
                    result: nResult,
                    msg: strErrmsg
                });
                return;
            }

            var strSql = '';
            updateArr.forEach((updateObj: any) => {
                updateObj.redisCluster = JSON.stringify(updateObj.redisCluster);
                updateObj.allowedAppids = JSON.stringify(updateObj.allowedAppids);
                var serviceId = updateObj.serviceId;
                delete updateObj.serviceId;
                updateObj.id = serviceId;
                strSql += mysql.format(`update ${tableName} SET ? where id = ${serviceId} ;`, updateObj);
            });

            connection.query(strSql, (err: any, results: any) => {
                if (err) {
                    logger.error('updateService ', err);
                    sendMysqlErr(res, err, strSql);
                    return;
                }
                var nTotalAffectedRow = 0;
                results.forEach((item: any) => {
                    nTotalAffectedRow += item.affectedRows;
                });
                res.send({
                    affectedRows: nTotalAffectedRow,
                    result: nResult,
                    msg: strErrmsg
                });
            });
        });
    }
    updateServiceState(serviceId: number, code: number, errmsg: string) {
        let sql: string = mysql.format(`update ${tableName} SET ? where id= ${serviceId};`, [{
            status: code,
            msg: errmsg
        }]);
        connection.query(sql);
    }

    getServices(cb: GetServicesCb) {
        var sql = 'select * from tb_service_info';
        connection.query(sql, (err: any, results: any) => {
            var retObj: ServiceList = new ServiceList();
            if (!err) {
                var nLen = results.length;
                var nResult = 1;
                var strErrmsg = 'ok';
                for (var i = 0; i < nLen; ++i) {
                    var entry = results[i];
                    var redisClusterArr: RedisHost[] = [];
                    var allowedAppidsObj: string[] = [];

                    try {
                        redisClusterArr = JSON.parse(entry.redisCluster);
                        allowedAppidsObj = JSON.parse(entry.allowedAppids);//如果allowedAppids不是json对象，解析会出异常，这里需要补货。
                    }
                    catch (e) {
                        logger.error('解析redisCluster或allowedAppids失败，servicdId: ' + entry.id);
                        nResult = -1;
                        strErrmsg = '解析allowedAppids失败, serviceId: ' + entry.id;
                        break;
                    }
                    var service: Service = new Service();
                    service.serviceId = entry.id;
                    service.redisCluster = redisClusterArr;
                    service.mysqlAddr = entry.mysqlAddr;
                    service.mysqlPort = entry.mysqlPort;
                    service.mysqlUser = entry.mysqlUser;
                    service.mysqlPwd = entry.mysqlPwd;
                    service.mysqlDbname = entry.mysqlDbname;
                    service.wxServiceAddr = entry.wxServiceAddr;
                    service.agentAddr = entry.agentAddr;
                    service.allowedAppids = allowedAppidsObj;
                    service.description = entry.description;
                    service.status = entry.status;
                    service.msg = entry.msg;

                    retObj.addService(service);
                }
                retObj.setMsg(strErrmsg);
                retObj.setResult(nResult);
                cb(null, retObj);
            }
            else {
                logger.info(`errmsg: ${err}`);
                retObj.setResult(-1);
                retObj.setMsg(`dbError, errmsg: ${err}`);
                cb(new Error(err.message), retObj);
            }
        });
    }
}
export default MysqlHandler;